import * as NSNodeFileSys from "fs";
import * as NSNodePath from "path";
import * as NSVscode from "vscode";
import { stringToUint8Array } from "./string-util";

export interface VueComponentFilesPath {
  scriptFilePath: string,
  styleFilePath: string,
  vueFilePath: string,
}

export interface VueComponentFileName {
  vueFileName: string,
  styleFileName: string,
  scriptFileName: string,
}

export const styleSuffixList = [
  "scss",
  "sass",
  "less",
  "css",
] as const;

export const scriptSuffixBaseList = [
  "js",
  "ts"
] as const;

export type StyleLang = (typeof styleSuffixList)[number];
export type ScriptLang = (typeof scriptSuffixBaseList)[number];
export type ScriptSuffix = ScriptLang | `m${ScriptLang}` | `c${ScriptLang}` | `${ScriptLang}x` | `m${ScriptLang}x` | `c${ScriptLang}x`;

export function getScriptLangFromSuffix(
  scriptSuffix: ScriptSuffix
): ScriptLang {
  let scriptLang: string = scriptSuffix;
  if (
    scriptSuffix.startsWith("m") ||
    scriptSuffix.startsWith("c")
  ) {
    scriptLang = scriptLang.slice(1);
  }
  if (scriptSuffix.endsWith("x")) {
    scriptLang = scriptLang.slice(0, scriptLang.length - 1);
  }
  return scriptLang as ScriptLang;
}


export function getScssContent(kebabCaseName: string) {
  return `.c-${kebabCaseName} {\n}`;
}

export function getVueContent(
  kebabCaseName: string,
  scriptLang: ScriptLang,
  scriptFileName: string,
  styleLang: StyleLang,
  styleFileName: string,
) {
  return `<template>
  <div class="c-${kebabCaseName}"></div>
</template>

<script
  lang="${scriptLang}"
  src="./${scriptFileName}"
></script>

<style 
  lang="${styleLang}"
  scoped 
  src="./${styleFileName}"
></style>
`;
}

export function getTsContent(pascalCaseName: string) {
  return `
import { defineComponent } from "vue"; 

export default defineComponent({
  name: "${pascalCaseName}",
  components: {
  },
  props: {
  },
  setup() {
    return {};
  },
  data: () => {
    return {};
  },
  computed: {
  },
  watch: {
  },
  methods: {
  },
});

`;
}

/**
 * 
 * @param vueFilePath -- 绝对路径
 * @param kebabCaseName 
 * @param scriptLang 
 * @param scriptFileName 
 * @param styleLang 
 * @param styleFileName 
 * @returns 
 */
export function createVueFile(
  vueFilePath: string,
  kebabCaseName: string,
  scriptLang: "ts" | "js",
  scriptFileName: string,
  styleLang: StyleLang,
  styleFileName: string,
): Thenable<void> {
  const fileContent = getVueContent(kebabCaseName, scriptLang, scriptFileName, styleLang, styleFileName);
  return NSVscode.workspace.fs.writeFile(
    NSVscode.Uri.file(vueFilePath),
    stringToUint8Array(fileContent)
  );
}


export function createStyleFile(
  styleFilePath: string,
  kebabCaseName: string
): Thenable<void> {
  const styleContent = getScssContent(kebabCaseName);
  return NSVscode.workspace.fs.writeFile(
    NSVscode.Uri.file(styleFilePath),
    stringToUint8Array(styleContent)
  );
}

export function createScriptFile(
  scriptFilePath: string,
  pascalCaseName: string,
): Thenable<void> {
  const scriptContent = getTsContent(pascalCaseName);
  return NSVscode.workspace.fs.writeFile(
    NSVscode.Uri.file(scriptFilePath),
    stringToUint8Array(scriptContent)
  );
}

export async function createVueComponentFiles(
  componentDirPath: string,
  pascalCaseName: string,
  kebabCaseName: string,
  styleSuffix: StyleLang,
  scriptSuffix: ScriptSuffix,
): Promise<VueComponentFileName & VueComponentFilesPath> {
  const scriptLang = getScriptLangFromSuffix(scriptSuffix);
  const dirPath = NSNodePath.join(componentDirPath, pascalCaseName);
  const isDirExist = NSNodeFileSys.existsSync(dirPath);
  if (!isDirExist) {
    await NSNodeFileSys.promises.mkdir(dirPath, {
      recursive: true,
    });
  }
  const scriptFileName = "VDC" + pascalCaseName + "." + scriptSuffix;
  const styleFileName = `Scope${pascalCaseName}.${styleSuffix}`;
  const vueFileName = pascalCaseName + ".vue";
  const vueFilePath = NSNodePath.join(dirPath, vueFileName);
  const styleFilePath = NSNodePath.join(dirPath, styleFileName);
  const scriptFilePath = NSNodePath.join(dirPath, scriptFileName);
  return Promise.all([
    createVueFile(
      vueFilePath,
      kebabCaseName,
      scriptLang,
      scriptFileName,
      styleSuffix,
      styleFileName
    ),
    createStyleFile(
      NSNodePath.join(dirPath, styleFileName),
      kebabCaseName
    ),
    createScriptFile(
      NSNodePath.join(dirPath, scriptFileName),
      pascalCaseName
    )
  ]).then(() => {
    return {
      vueFilePath,
      styleFilePath,
      scriptFilePath,
      vueFileName,
      styleFileName,
      scriptFileName
    };
  });
}
